using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace HalconDotNet
{
	[ToolboxBitmap(typeof(HWindowControlWPF), "HWindowControlWPF.icon.bmp")]
	public class HWindowControlWPF : UserControl, IDisposable
	{
		private Canvas windowCanvas;

		private HWindowWPF windowWPF;

		private HWindow window;

		private Rect imagePart = new Rect(0.0, 0.0, 640.0, 480.0);

		internal Canvas Container => windowCanvas;

		public HWindow HalconWindow
		{
			get
			{
				if (window != null)
				{
					return window;
				}
				return new HWindow();
			}
		}

		public IntPtr HalconID
		{
			get
			{
				if (window != null)
				{
					return window.Handle;
				}
				return HHandleBase.UNDEF;
			}
		}

		public Rect ImagePart
		{
			get
			{
				if (windowWPF != null && windowWPF.HalconWindow != null)
				{
					windowWPF.HalconWindow.GetPart(out int row, out int column, out int row2, out int column2);
					imagePart = new Rect(column, row, column2 - column + 1, row2 - row + 1);
				}
				return imagePart;
			}
			set
			{
				imagePart = new Rect((int)value.Left, (int)value.Top, (int)value.Width, (int)value.Height);
				UpdatePart();
			}
		}

		public event HInitWindowEventHandlerWPF HInitWindow;

		public event HMouseEventHandlerWPF HMouseMove;

		public event HMouseEventHandlerWPF HMouseDown;

		public event HMouseEventHandlerWPF HMouseUp;

		public event HMouseEventHandlerWPF HMouseWheel;

		public HWindowControlWPF()
		{
			windowCanvas = new Canvas();
			windowCanvas.Margin = new Thickness(0.0, 0.0, 0.0, 0.0);
			windowCanvas.Background = System.Windows.Media.Brushes.Red;
			windowCanvas.Height = double.NaN;
			windowCanvas.Width = double.NaN;
			base.Content = windowCanvas;
			windowCanvas.Loaded += windowCanvas_Loaded;
			windowCanvas.SizeChanged += windowCanvas_SizeChanged;
			base.Width = double.NaN;
			base.Height = double.NaN;
			base.Background = System.Windows.Media.Brushes.LightGreen;
		}

		private void ApplyScalingFactor(Visual visual)
		{
			PresentationSource presentationSource = PresentationSource.FromVisual(visual);
			if (presentationSource != null)
			{
				Matrix transformToDevice = presentationSource.CompositionTarget.TransformToDevice;
				double m = transformToDevice.M11;
				double m2 = transformToDevice.M22;
				if (m != 0.0 && m != 0.0)
				{
					double scaleX = 1.0 / m;
					double scaleY = 1.0 / m2;
					windowCanvas.LayoutTransform = new ScaleTransform(scaleX, scaleY);
					windowCanvas.UpdateLayout();
				}
			}
		}

		private void windowCanvas_Loaded(object sender, RoutedEventArgs e)
		{
			if (windowWPF == null)
			{
				windowCanvas.Background = System.Windows.Media.Brushes.Black;
				if (base.IsVisible)
				{
					ApplyScalingFactor(this);
				}
				else
				{
					windowCanvas.IsVisibleChanged += windowCanvas_IsVisibleChanged;
				}
				if (!DesignerProperties.GetIsInDesignMode(this))
				{
					try
					{
						HOperatorSet.GenEmptyObj(out HObject emptyObject);
						emptyObject.Dispose();
						windowWPF = new HWindowWPF(this);
						windowWPF.HWButtonEvent += windowWPF_ButtonEvent;
						windowWPF.HWMouseEvent += windowWPF_MouseEvent;
						windowWPF.HWInitEvent += windowWPF_InitEvent;
						windowCanvas.Children.Add(windowWPF);
					}
					catch (DllNotFoundException)
					{
					}
				}
			}
		}

		private void windowCanvas_SizeChanged(object sender, SizeChangedEventArgs e)
		{
			if (windowWPF != null)
			{
				try
				{
					windowWPF.SetWindowExtents((int)windowCanvas.ActualWidth, (int)windowCanvas.ActualHeight);
					if (HSystem.GetSystem(new HTuple("flush_graphic")).S == "true")
					{
						windowWPF.UpdateLayout();
					}
				}
				catch (HOperatorException)
				{
				}
			}
		}

		private void windowCanvas_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
		{
			if ((bool)e.NewValue)
			{
				ApplyScalingFactor(this);
				windowCanvas.IsVisibleChanged -= windowCanvas_IsVisibleChanged;
			}
		}

		private void UpdatePart()
		{
			if (windowWPF != null && windowWPF.HalconWindow != null)
			{
				windowWPF.HalconWindow.SetPart((int)imagePart.Top, (int)imagePart.Left, (int)(imagePart.Top + imagePart.Height - 1.0), (int)(imagePart.Left + imagePart.Width - 1.0));
			}
		}

		public void SetFullImagePart(HImage reference)
		{
			reference.GetImagePointer1(out string _, out int width, out int height);
			imagePart = new Rect(0.0, 0.0, width, height);
			UpdatePart();
		}

		public new bool Focus()
		{
			base.Focusable = true;
			windowWPF.SetNativeFocus();
			return true;
		}

		void IDisposable.Dispose()
		{
			Dispose();
		}

		public virtual void Dispose()
		{
			if (windowWPF != null)
			{
				windowWPF.Dispose();
				windowWPF = null;
			}
		}

		protected virtual void OnHInitWindow()
		{
			if (this.HInitWindow != null)
			{
				this.HInitWindow(this, new EventArgs());
			}
		}

		protected virtual void OnHMouseMove(HMouseEventArgsWPF e)
		{
			if (this.HMouseMove != null)
			{
				this.HMouseMove(this, e);
			}
		}

		protected virtual void OnHMouseDown(HMouseEventArgsWPF e)
		{
			if (this.HMouseDown != null)
			{
				this.HMouseDown(this, e);
			}
		}

		protected virtual void OnHMouseUp(HMouseEventArgsWPF e)
		{
			if (this.HMouseUp != null)
			{
				this.HMouseUp(this, e);
			}
		}

		protected virtual void OnHMouseWheel(HMouseEventArgsWPF e)
		{
			if (this.HMouseWheel != null)
			{
				this.HMouseWheel(this, e);
			}
		}

		private HMouseEventArgsWPF ToHMouse(int x, int y, MouseButton? button, int delta)
		{
			double rowImage;
			double columnImage;
			if (window == null)
			{
				rowImage = ((windowWPF == null) ? ((double)y) : (imagePart.Top + (double)y * imagePart.Height / windowWPF.Height));
				columnImage = ((windowWPF == null) ? ((double)x) : (imagePart.Left + (double)x * imagePart.Width / windowWPF.Width));
			}
			else
			{
				window.ConvertCoordinatesWindowToImage(y, x, out rowImage, out columnImage);
			}
			return new HMouseEventArgsWPF(x, y, rowImage, columnImage, delta, button);
		}

		private void windowWPF_InitEvent()
		{
			window = windowWPF.HalconWindow;
			UpdatePart();
			base.Focusable = true;
			OnHInitWindow();
		}

		private void windowWPF_ButtonEvent(int x, int y, MouseButton button, MouseButtonState state)
		{
			if (state == MouseButtonState.Released)
			{
				OnHMouseUp(ToHMouse(x, y, button, 0));
				return;
			}
			OnHMouseDown(ToHMouse(x, y, button, 0));
			if (base.Focusable)
			{
				windowWPF.SetNativeFocus();
			}
		}

		private void windowWPF_MouseEvent(int x, int y, MouseButton? button, int delta)
		{
			if (delta == 0)
			{
				OnHMouseMove(ToHMouse(x, y, button, 0));
			}
			else
			{
				OnHMouseWheel(ToHMouse(x, y, null, delta));
			}
		}
	}
}
